package com.ztesoft.zsmart.zcm.dialing.util;

import com.ztesoft.dcc.message.Avp;
import com.ztesoft.dcc.message.Dcc;
import com.ztesoft.zsmart.core.log.ZSmartLogger;
import com.ztesoft.zsmart.zcm.dialing.config.DialingProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Weiping Ye
 * @version 创建时间：2013-4-9 下午3:54:45
 **/
@Component
public class DccUtil {
    private static ZSmartLogger logger = ZSmartLogger.getLogger(DccUtil.class);
    public static final int AVP_CODE_HOST_IP_ADDRESS = 257;
    public static final int AVP_CODE_APPLICATION_ID = 258;
    public static final int AVP_CODE_VENDOR_ID = 266;
    public static final int AVP_CODE_RESULT_CODE = 268;
    public static final int AVP_CODE_PRODUCT_NAME = 269;
    public static final int AVP_CODE_ORIGIN_STATE_ID = 278;
    public static final int AVP_CODE_SESSION_ID = 263;
    public static final int AVP_CODE_REQUEST_ACTION = 436;
    public static final int AVP_CODE_ORIGIN_HOST = 264;
    public static final int AVP_CODE_ORIGIN_REALM = 296;
    public static final int AVP_CODE_DESTINATION_REALM = 283;
    public static final int AVP_CODE_DESTINATION_HOST = 293;
    public static final int AVP_CODE_CC_CORRELATION_ID = 411;
    public static final int AVP_CODE_SERVICE_CONTEXT_ID = 461;
    public static final int AVP_CODE_SERVICE_INFORMATION = 873;
    public static final int AVP_CODE_SERVICE_RESULT_CODE = 20631;
    public static final int AVP_CODE_BIMP_INFORMATION = 80914;
    public static final int AVP_CODE_BIMP_TYPE = 80915;
    public static final int AVP_CODE_BIMP_COMMAND = 80916;
    public static final int AVP_CODE_BIMP_TASK_ID = 80917;
    public static final int AVP_CODE_BIMP_TASK_PARAM = 80918;
    public static final int AVP_CODE_DATA_INFORMATION = 80400;
    public static final int AVP_CODE_DATA_TABLE_SIMPLE_ROW = 80406;

    public static final String AVP_VALUE_RESULT_CODE = "2001";

    public static final String AVP_VALUE_BIMP_TYPE_MANAGER = "100";
    public static final String AVP_VALUE_BIMP_TYPE_OLC = "0";

    //CER:能力交换包 CCR:普通请求包 DWR:心跳包
    public static final int DCC_CODE_CER = 257;
    public static final int DCC_CODE_CEA = 257;
    public static final int DCC_CODE_CCR = 272;
    public static final int DCC_CODE_CCA = 272;
    public static final int DCC_CODE_DWR = 280;
    public static final int DCC_CODE_DWA = 280;

    private static AtomicInteger sessionIdCounter = new AtomicInteger(0);

    @Autowired
    private DialingProperties dialingProperties;
    private Avp generateSessionId() {
        Avp sessionId = new Avp();
        sessionId.setCode(AVP_CODE_SESSION_ID);
        sessionId.setValue(dialingProperties.getOriginHost() + ";" +
            System.currentTimeMillis() + ";" + sessionIdCounter.getAndIncrement());
        return sessionId;
    }

    private Avp generateRequestAction() {
        return new Avp(AVP_CODE_REQUEST_ACTION, dialingProperties.getRequestAction());
    }

    private Avp generateResultCode() {
        Avp resultCode = new Avp();
        resultCode.setCode(AVP_CODE_RESULT_CODE).setValue(AVP_VALUE_RESULT_CODE);

        return resultCode;
    }
    private Avp generateOriginHost() {
        Avp originHost = new Avp();
        originHost.setCode(AVP_CODE_ORIGIN_HOST)
            .setValue(dialingProperties.getOriginHost())
            .setmFlag(true);

        return originHost;
    }
    private Avp generateOriginRealm() {
        Avp originRealm = new Avp();
        originRealm.setCode(AVP_CODE_ORIGIN_REALM);
        originRealm.setValue(dialingProperties.getOriginRealm()).setmFlag(true);
        return originRealm;
    }
    private Avp generateDestinationHost() {
        Avp destinationHost = new Avp();
        destinationHost.setCode(AVP_CODE_DESTINATION_HOST);
        destinationHost.setValue(dialingProperties.getDestHost());
        return destinationHost;
    }
    private Avp generateDestinationRealm() {
        Avp originRealm = new Avp();
        originRealm.setCode(AVP_CODE_DESTINATION_REALM);
        originRealm.setValue(dialingProperties.getDestRealm());
        return originRealm;
    }

    private Avp generateAuthApplicationId() {
        Avp applicationId = new Avp(AVP_CODE_APPLICATION_ID, dialingProperties.getAuthApplicationId());
        return applicationId;
    }

    private Avp generateServiceContextId() {
        Avp serviceContextId = new Avp();
        serviceContextId.setCode(AVP_CODE_SERVICE_CONTEXT_ID);
        serviceContextId.setValue(dialingProperties.getServiceContextId());

        return serviceContextId;
    }

    private Avp generateOriginStateId() {
        return new Avp(AVP_CODE_ORIGIN_STATE_ID, String.valueOf(System.currentTimeMillis()));
    }

    public static final int AVP_CODE_CC_REQUEST_TYPE = 416;
    private Avp generateCCRqeustType() {
        Avp avp = new Avp();
        avp.setCode(AVP_CODE_CC_REQUEST_TYPE).setValue(dialingProperties.getCcRequestType());
        return avp;
    }

    public static final int AVP_CODE_CC_REQUEST_NUMBER = 415;
    private Avp generateCCRqeustNumber() {
        Avp avp = new Avp();
        avp.setCode(AVP_CODE_CC_REQUEST_NUMBER).setValue(dialingProperties.getCcRequestNumber());
        return avp;
    }

    public static BigInteger createBigInteger() {
        SecureRandom random = new SecureRandom();
        long id = random.nextInt(10000000);
        return new BigInteger(String.valueOf(id));
    }

    public Dcc generateCcr(String bimpTaskParam) {
        Dcc ccr = new Dcc();
        ccr.setrFlag(true);
        ccr.setCommandCode(DCC_CODE_CCR);
        ccr.setApplicationId(dialingProperties.getApplicationId());
        // hop-by-hob-id取当前时间
        ccr.setHopbyhopId(createBigInteger());
        // end-by-end-id取当前时间
        ccr.setEndbyendId(createBigInteger());

        ccr.addAvp(generateSessionId());
        ccr.addAvp(generateOriginHost());
        ccr.addAvp(generateOriginRealm());
        ccr.addAvp(generateDestinationHost());
        ccr.addAvp(generateDestinationRealm());
        ccr.addAvp(generateAuthApplicationId());
        ccr.addAvp(generateServiceContextId());
        ccr.addAvp(generateCCRqeustType());
        ccr.addAvp(generateCCRqeustNumber());

        Avp bimpTaskParamAvp = new Avp();
        bimpTaskParamAvp.setCode(AVP_CODE_BIMP_TASK_PARAM);
        bimpTaskParamAvp.setValue(bimpTaskParam);

        Avp bimpType = new Avp();
        bimpType.setCode(AVP_CODE_BIMP_TYPE);
        bimpType.setValue(AVP_VALUE_BIMP_TYPE_MANAGER);

        Avp bimpTaskId = new Avp();
        bimpTaskId.setCode(AVP_CODE_BIMP_TASK_ID);
        bimpTaskId.setValue("");

        Avp bimpInfomation = new Avp();
        bimpInfomation.setCode(AVP_CODE_BIMP_INFORMATION);
        bimpInfomation.addSubAvp(bimpTaskParamAvp);
        bimpInfomation.addSubAvp(bimpType);
        bimpInfomation.addSubAvp(bimpTaskId);

        Avp serviceInfomation = new Avp();
        serviceInfomation.setCode(AVP_CODE_SERVICE_INFORMATION);
        serviceInfomation.addSubAvp(bimpInfomation);

        ccr.addAvp(serviceInfomation);
        ccr.buildAvpMap();

        return ccr;
    }

    public Dcc generateCca(Dcc ccr) {
        Dcc cca = new Dcc();
        cca.setrFlag(true);
        cca.setCommandCode(DCC_CODE_CCA);
//        cca.setApplicationId(ccr.getApplicationId());
        // hop-by-hob-id取当前时间
        cca.setHopbyhopId(ccr.getHopbyhopId());
        // end-by-end-id取当前时间
        cca.setEndbyendId(ccr.getEndbyendId());
        cca.addAvp(generateResultCode())
//            .addAvp(generateOriginHost())
//            .addAvp(generateOriginRealm())
            .buildAvpMap();
        return cca;
    }

    public Dcc generateCcrForOlc(String bimpTaskIdValue, String bimpTaskParam) {
        Dcc ccr = new Dcc();
        ccr.setrFlag(true);
        ccr.setCommandCode(DCC_CODE_CCR);
        ccr.setApplicationId(dialingProperties.getApplicationId());
        // hop-by-hob-id取当前时间
        ccr.setHopbyhopId(createBigInteger());
        // end-by-end-id取当前时间
        ccr.setEndbyendId(createBigInteger());

        ccr.addAvp(generateSessionId());
        ccr.addAvp(generateRequestAction());
        ccr.addAvp(generateOriginHost());
        ccr.addAvp(generateOriginRealm());
        ccr.addAvp(generateDestinationHost());
        ccr.addAvp(generateDestinationRealm());
        ccr.addAvp(generateAuthApplicationId());
        ccr.addAvp(generateServiceContextId());
        ccr.addAvp(generateCCRqeustType());
        ccr.addAvp(generateCCRqeustNumber());

        Avp bimpType = new Avp();
        bimpType.setCode(AVP_CODE_BIMP_TYPE);
        bimpType.setValue(AVP_VALUE_BIMP_TYPE_OLC);

        Avp bimpInfomation = new Avp();
        bimpInfomation.setCode(AVP_CODE_BIMP_INFORMATION).addSubAvp(bimpType);

        if (bimpTaskIdValue != null) {
            Avp bimpTaskId = new Avp();
            bimpTaskId.setCode(AVP_CODE_BIMP_TASK_ID);
            bimpTaskId.setValue(bimpTaskIdValue);

            bimpInfomation.addSubAvp(bimpTaskId);
        }
        if (bimpTaskParam != null) {
            Avp bimpTaskParamAvp = new Avp();
            bimpTaskParamAvp.setCode(AVP_CODE_BIMP_TASK_PARAM);
            bimpTaskParamAvp.setValue(bimpTaskParam);
            bimpInfomation.addSubAvp(bimpTaskParamAvp);
        }

        Avp serviceInfomation = new Avp();
        serviceInfomation.setCode(AVP_CODE_SERVICE_INFORMATION);
        serviceInfomation.addSubAvp(bimpInfomation);

        ccr.addAvp(serviceInfomation);
        ccr.buildAvpMap();

        return ccr;
    }

    public Dcc generateCer() {
        Dcc cer = new Dcc();
        cer.setrFlag(true);
        cer.setpFlag(false);
        cer.setCommandCode(DCC_CODE_CER);
        cer.setApplicationId(1);
        cer.setApplicationId(dialingProperties.getApplicationId());
        // hop-by-hob-id取当前时间
        cer.setHopbyhopId(createBigInteger());
        // end-by-end-id取当前时间
        cer.setEndbyendId(createBigInteger());

        cer.addAvp(generateSessionId());
        cer.addAvp(generateOriginHost());
        cer.addAvp(generateOriginRealm());
        cer.addAvp(generateOriginStateId());
        cer.addAvp(generateHostIpAddress());

        cer.addAvp(generateProductName());
        Avp vendorId = new Avp();
        vendorId.setCode(AVP_CODE_VENDOR_ID);
        vendorId.setValue(dialingProperties.getVendorId());
        //        vendorId.setValue("0");
        vendorId.setmFlag(true);
        cer.addAvp(vendorId);

        cer.addAvp(generateAuthApplicationId());

        cer.buildAvpMap();

        return cer;
    }

    public Dcc generateCea() {
        Dcc cea = new Dcc();
        cea.setpFlag(false);
        cea.setCommandCode(DCC_CODE_CEA);
        cea.setrFlag(false)
            .addAvp(generateResultCode())
//            .addAvp(generateOriginHost())
//            .addAvp(generateOriginRealm())
            .buildAvpMap();
        return cea;
    }
    private Avp generateHostIpAddress() {
        Avp hostIpAddress = new Avp();
        hostIpAddress.setCode(AVP_CODE_HOST_IP_ADDRESS);
        try {
            hostIpAddress.setValue(Inet4Address.getLocalHost().getHostAddress());
        }
        catch (UnknownHostException e) {
            logger.error(e.getMessage(), e);
        }
        hostIpAddress.setmFlag(true);
        return hostIpAddress;
    }

    private Avp generateProductName() {
        Avp productName = new Avp();
        productName.setCode(AVP_CODE_PRODUCT_NAME).setValue(dialingProperties.getProductName()).setmFlag(true);
        return productName;
    }

    public Dcc generateDwr() {
        Dcc dwr = new Dcc();
        dwr.setCommandCode(DCC_CODE_DWR);
        dwr.setrFlag(true)
            .addAvp(generateOriginHost())
            .addAvp(generateOriginRealm())
            .buildAvpMap();
        return dwr;
    }

    public Dcc generateDwa() {
        Dcc dwa = new Dcc();
        dwa.setCommandCode(DCC_CODE_DWA);
        dwa.setrFlag(false)
            .addAvp(generateResultCode())
            .addAvp(generateOriginHost())
            .addAvp(generateOriginRealm())
            .buildAvpMap();
        return dwa;
    }

}
